package com.xray.netdisk;

import com.xray.netdisk.pojo.FileItem;
import com.xray.netdisk.pojo.User;
import com.xray.netdisk.service.FileService;
import com.xray.netdisk.service.UserService;
import com.xray.netdisk.service.impl.FileServiceImpl;
import com.xray.netdisk.service.impl.UserServiceImpl;
import com.xray.netdisk.utils.FileUtils;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.xray.netdisk.utils.FileUtils.*;

/**
 * 服务器V2
 */
public class ServerV2 {

    //线程池
    private ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    //用户逻辑
    private UserService userService = new UserServiceImpl();
    //文件逻辑
    private FileService fileService = new FileServiceImpl();

    /**
     * 处理客户端登录
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public synchronized void handleLogin(DataInputStream inputStream,DataOutputStream outputStream) throws IOException{
        //读取账号，密码
        String username = inputStream.readUTF();
        String password = inputStream.readUTF();
        System.out.printf("用户账号%s密码%s\n",username,password);
        //登录
        User user = userService.login(username, password);
        //登录成功，发送用户id给客户端，否则发送-1
        if(user != null){
            outputStream.writeLong(user.getId());
        }else{
            outputStream.writeLong(-1);
        }
        outputStream.flush();
        outputStream.close();
    }

    /**
     * 处理客户端文件查询
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public synchronized void handleListFiles(DataInputStream inputStream,DataOutputStream outputStream) throws IOException {
        //读取客户端用户id
        long userId = inputStream.readLong();
        //查询该用户的文件列表
        List<FileItem> fileItems = fileService.getFileItemsByUserId(userId);
        //发送JSON
        outputStream.writeUTF(FileUtils.listToJSON(fileItems));
        outputStream.close();
    }

    /**
     * 处理客户端文件上传
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public synchronized void handleUpload(DataInputStream inputStream,DataOutputStream outputStream) throws IOException {
        //读取文件名
        String fileName = inputStream.readUTF();
        if("error".equals(fileName)){
            System.out.println("客户端上传失败");
            return;
        }
        //读取用户id
        long userId = inputStream.readLong();
        //查询用户
        User user = userService.getUserById(userId);
        //如果用户的上传目录不存在，就创建
        File userDir = new File(UPLOAD_DIR+"\\"+user.getUsername());
        if(!userDir.exists()){
            userDir.mkdirs();
        }
        //文件上传
        File file = new File(userDir, fileName);
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        FileUtils.io(inputStream,fileOutputStream);
        //查询数据库中的文件
        FileItem item = fileService.getFileItemByUserIdAndFilename(userId, fileName);
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        if(item == null){
            //如果文件信息不存在，就添加数据
            item = new FileItem(0L,file.getName(),file.getAbsolutePath(),file.length(),userId,0,user.getUsername(),time);
            fileService.addFileItem(item);
        }else{
            //文件信息存在，就修改长度和创建时间
            item.setCreateTime(time);
            item.setLength(file.length());
            fileService.modifyFileItem(item);
        }
    }

    /**
     * 处理下载
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public synchronized void handleDownload(DataInputStream inputStream,DataOutputStream outputStream) throws IOException {
        //读取文件id
        long fileId = inputStream.readLong();
        //查询文件
        FileItem fileItem = fileService.getFileItemById(fileId);
        File file = new File(fileItem.getPath());
        //如果文件存在就发送给客户端
        if(!file.exists()){
            outputStream.writeUTF("error");
        }else {
            outputStream.writeUTF(file.getName());
            FileInputStream fileInputStream = new FileInputStream(file);
            FileUtils.io(fileInputStream, outputStream);
        }
    }

    /**
     * 处理删除文件
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public synchronized void handleDelete(DataInputStream inputStream,DataOutputStream outputStream) throws IOException {
        //读取文件id
        long fileId = inputStream.readLong();
        //查询文件
        FileItem fileItem = fileService.getFileItemById(fileId);
        File file = new File(fileItem.getPath());
        //存在就删除磁盘和数据库上的文件
        if(!file.exists()){
            outputStream.writeUTF("error");
        }else {
            file.delete();
            fileService.removeFileItem(fileId);
            outputStream.writeUTF("ok");
        }
    }

    /**
     * 服务器启动
     */
    public void start(){
        System.out.println("启动网盘服务器");
        try(ServerSocket serverSocket = new ServerSocket(PORT)){
            for(;;){
                Socket accept = serverSocket.accept();
                //获得客户端连接后，使用线程池启动单独的线程来处理
                threadPool.execute(()->{
                    try(DataInputStream input = new DataInputStream(accept.getInputStream());
                        DataOutputStream output = new DataOutputStream(accept.getOutputStream());){
                        //判断客户端要执行的操作
                        int type = input.readInt();
                        switch(type){
                            case TYPE_LOGIN:
                                System.out.printf("用户%s登录\n" ,accept.getInetAddress());
                                handleLogin(input,output);
                                break;
                            case TYPE_LIST:
                                System.out.printf("用户%s查询文件列表\n" ,accept.getInetAddress());
                                handleListFiles(input,output);
                                break;
                            case TYPE_UPLOAD:
                                System.out.printf("用户%s上传文件\n" ,accept.getInetAddress());
                                handleUpload(input,output);
                                break;
                            case TYPE_DOWNLOAD:
                                System.out.printf("用户%s下载文件\n" ,accept.getInetAddress());
                                handleDownload(input,output);
                                break;
                            case TYPE_DELETE:
                                System.out.printf("用户%s删除文件\n" ,accept.getInetAddress());
                                handleDelete(input,output);
                                break;
                        }
                    }catch (IOException ex){
                        ex.printStackTrace();
                    }
                });
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new ServerV2().start();
    }

}
